package com.sushengren.easyword.handle;

import com.sushengren.easyword.anchor.Anchor;
import com.sushengren.easyword.anchor.BookmarkAnchor;
import com.sushengren.easyword.anchor.PlaceholderAnchor;
import com.sushengren.easyword.enums.DataTypeEnum;
import com.sushengren.easyword.model.AnchorContext;
import com.sushengren.easyword.model.WriteData;
import com.sushengren.easyword.util.ImageUtil;
import com.sushengren.easyword.util.IoUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.w3c.dom.Node;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 写入数据处理
 *
 * @author sushengren
 */
public class WriteDataHandle implements AnchorHandle {

    @Override
    public void handle(AnchorContext anchorContext, WriteData writeData) {
        if (writeData != null) {
            switch (getDataType(anchorContext, writeData)) {
                case STRING:
                    writeString(anchorContext, writeData);
                    break;
                case PICTURE:
                    writePicture(anchorContext, writeData);
                    break;
                case LIST:
                    if (!CollectionUtils.isEmpty(anchorContext.getNodeList())) {
                        writeList(anchorContext, writeData);
                    }
                    break;
            }
        }
    }

    /**
     * 写入字符串
     *
     * @param anchorContext 锚点下文
     * @param writeData     写入的数据
     */
    private void writeString(AnchorContext anchorContext, WriteData writeData) {
        Anchor anchor = anchorContext.getAnchor();
        List<WriteData> flatten = flatten(writeData, anchorContext.getKey());
        String stringValue = flatten.get(Math.min(flatten.size() - 1, anchorContext.getKeyIndex())).getStringValue();
        if (anchor instanceof PlaceholderAnchor) {
            List<XWPFRun> runs = anchorContext.getRuns();
            if (runs.isEmpty()) {
                throw new IllegalArgumentException("未找到插入的锚点");
            }
            for (XWPFRun run : runs) {
                if (!flatten.isEmpty() && "".equals(run.text())) {
                    if (stringValue.contains(PlaceholderAnchor.LINE_SPLIT)) {
                        for (String split : stringValue.split(PlaceholderAnchor.LINE_SPLIT)) {
                            run.setText(split);
                            run.addBreak();
                        }
                    } else {
                        run.setText(stringValue);
                    }
                    break;
                }
            }
        }
        if (anchor instanceof BookmarkAnchor) {
            List<XWPFRun> runs = anchorContext.getRuns();
            if (!CollectionUtils.isEmpty(runs)) {
                for (XWPFRun run : runs) {
                    run.setText("", 0);
                }
                XWPFRun run = runs.get(0);
                if (!flatten.isEmpty()) {
                    if (stringValue.contains(PlaceholderAnchor.LINE_SPLIT)) {
                        for (String split : stringValue.split(PlaceholderAnchor.LINE_SPLIT)) {
                            run.setText(split);
                            run.addBreak();
                        }
                    } else {
                        run.setText(stringValue);
                    }
                }
            } else {
                List<Node> nodeList = anchorContext.getNodeList();
                Node node = nodeList.get(nodeList.size() - 1);
                Node parentNode = node.getParentNode();
                XWPFRun run = anchorContext.getParagraph().createRun();
                if (stringValue.contains(PlaceholderAnchor.LINE_SPLIT)) {
                    for (String split : stringValue.split(PlaceholderAnchor.LINE_SPLIT)) {
                        run.setText(split);
                        run.addBreak();
                    }
                } else {
                    run.setText(stringValue);
                }
                parentNode.insertBefore(run.getCTR().getDomNode(), node);
            }
        }
    }

    /**
     * 写入图片
     *
     * @param anchorContext 锚点下文
     * @param writeData     写入的数据
     */
    private void writePicture(AnchorContext anchorContext, WriteData writeData) {
        Anchor anchor = anchorContext.getAnchor();
        List<WriteData> flatten = flatten(writeData, anchorContext.getKey());
        BufferedImage image = ImageUtil.read(flatten.get(Math.min(flatten.size() - 1, anchorContext.getKeyIndex())).getValue());
        ByteArrayOutputStream out = null;
        ByteArrayInputStream in = null;
        try {
            out = new ByteArrayOutputStream();
            ImageIO.write(image, "png", out);
            in = new ByteArrayInputStream(out.toByteArray());

            final double scale = 1.9;
            final String filename = "01.png";
            int width = (int) (Units.toEMU(image.getWidth()) / scale);
            int height = (int) (Units.toEMU(image.getHeight()) / scale);
            if (anchor instanceof PlaceholderAnchor) {
                List<XWPFRun> runs = anchorContext.getRuns();
                if (runs.isEmpty()) {
                    throw new IllegalArgumentException("未找到插入的锚点");
                }
                runs.get(0).addPicture(in, XWPFDocument.PICTURE_TYPE_PNG, filename, width, height);
            }
            if (anchor instanceof BookmarkAnchor) {
                List<XWPFRun> runs = anchorContext.getRuns();
                if (!CollectionUtils.isEmpty(runs)) {
                    for (XWPFRun run : runs) {
                        run.setText("", 0);
                    }
                    runs.get(0).addPicture(in, XWPFDocument.PICTURE_TYPE_PNG, filename, width, height);
                } else {
                    List<Node> nodeList = anchorContext.getNodeList();
                    Node node = nodeList.get(nodeList.size() - 1);
                    Node parentNode = node.getParentNode();
                    XWPFRun run = anchorContext.getParagraph().createRun();
                    run.addPicture(in, XWPFDocument.PICTURE_TYPE_PNG, filename, width, height);
                    parentNode.insertBefore(run.getCTR().getDomNode(), node);
                }
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("插入图片异常", e);
        } finally {
            IoUtil.close(out);
            IoUtil.close(in);
        }
    }

    /**
     * 填充列表类型数据，暂时最高只支持两个层级
     *
     * @param anchorContext 锚点下文
     * @param writeData     填充数据对象
     */
    private void writeList(AnchorContext anchorContext, WriteData writeData) {
        List<Node> nodeList = anchorContext.getNodeList();
        Node firstNode = nodeList.get(0);
        Node parentNode = firstNode.getParentNode();

        for (List<WriteData> writeDataList : writeData.getListValue()) {
            Node childrenParentNode = null;
            List<Node> childrenParentNodeList = new ArrayList<>();
            if (anchorContext.getChildren() != null) {
                AnchorContext children = anchorContext.getChildren();
                List<Node> childrenNodeList = children.getNodeList();
                Node childrenFirstNode = childrenNodeList.get(0);
                childrenParentNode = childrenFirstNode.getParentNode();
                WriteData childrenWriteData = writeDataList.stream()
                        .filter(data -> children.getKey().endsWith(data.getKey())).findFirst().orElse(null);
                if (childrenWriteData != null) {
                    for (int i = 1; i < childrenWriteData.getListValue().size(); i++) {
                        List<Node> childrenCloneNodeList = cloneNodeList(childrenNodeList);
                        for (Node node : childrenCloneNodeList) {
                            childrenParentNode.insertBefore(node, childrenFirstNode);
                        }
                        childrenParentNodeList.addAll(childrenCloneNodeList);
                    }
                }
            }

            List<Node> cloneNodeList = cloneNodeList(nodeList);
            for (Node node : cloneNodeList) {
                parentNode.insertBefore(node, firstNode);
            }

            if (childrenParentNode != null && !childrenParentNodeList.isEmpty()) {
                childrenParentNodeList.forEach(childrenParentNode::removeChild);
                childrenParentNodeList.clear();
            }
        }

        nodeList.forEach(parentNode::removeChild);
    }

    /**
     * 克隆节点列表，排除书签节点
     *
     * @param nodeList 节点列表
     * @return 克隆的节点列表
     */
    private List<Node> cloneNodeList(List<Node> nodeList) {
        return nodeList.stream()
                .filter(node -> !BookmarkAnchor.BOOKMARK_START_FLAG.equals(node.getNodeName()))
                .filter(node -> !BookmarkAnchor.BOOKMARK_END_FLAG.equals(node.getNodeName()))
                .map(node -> node.cloneNode(true))
                .collect(Collectors.toList());
    }

    /**
     * 获取真实的填充数据类型
     *
     * @param anchorContext 锚点上下文
     * @param writeData     填充的数据对象
     * @return 数据类型
     */
    private DataTypeEnum getDataType(AnchorContext anchorContext, WriteData writeData) {
        String[] keys = anchorContext.getKey().split(PlaceholderAnchor.FLAG_SPLIT);
        if (keys.length <= 1) {
            return writeData.getDataType();
        }
        WriteData temporary = writeData;
        for (String key : keys) {
            for (List<WriteData> dataList : temporary.getListValue()) {
                for (WriteData data : dataList) {
                    if (data.getKey().equals(key)) {
                        temporary = data;
                        break;
                    }
                }
            }
        }
        return temporary.getDataType();
    }

    /**
     * 根据Key获取写入的数据列表
     *
     * @param writeData 写入的数据
     * @param key       Key
     * @return 数据列表
     */
    private List<WriteData> flatten(WriteData writeData, String key) {
        return flatten(writeData, key, new ArrayList<>(), null);
    }

    /**
     * 根据Key获取写入的数据列表
     *
     * @param writeData 写入的数据
     * @param key       Key
     * @param result    数据列表
     * @param prefix    Key前缀
     * @return 数据列表
     */
    private List<WriteData> flatten(WriteData writeData, String key, List<WriteData> result, String prefix) {
        WriteData item = new WriteData();
        item.setKey(prefix != null ? prefix + writeData.getKey() : writeData.getKey());
        item.setDataType(writeData.getDataType());
        item.setValue(writeData.getValue());
        item.setStringValue(writeData.getStringValue());
        if (key.equals(item.getKey())) {
            result.add(item);
        }
        if (writeData.getListValue() != null) {
            for (List<WriteData> dataList : writeData.getListValue()) {
                for (WriteData data : dataList) {
                    flatten(data, key, result, item.getKey() + PlaceholderAnchor.FLAG_SPLIT);
                }
            }
        }
        return result;
    }


}
